/**
 * @(#)Board2.java
 *
 *
 * @author 
 * @version 1.00 2008/4/28
 */
package Checkers;

import java.util.Arrays;

public class Board2 {
	private byte board[];
	private byte player;
	
    public Board2(byte player) {
    	for (int i=1; i<36; i++) {
    		if (i==9||i==18||i==27) { i++; continue; }
    		if (i < 14)
    			board[i] = 2;
    		else if (i < 23)
    			board[i] = 0;
    		else
    			board[i] = 1;
    	}
    	this.player = player;	// red = 1, black = 2
    }
    
    /**
     * PLAYER functions
     */
    public byte getPlayer() { return player; }
    public void nextPlayer() { player = (byte)((player > 1) ? 1 : 2); }
    
    /**
     * getBoard
     * returns the board, duh
     */
    public byte[] getBoard() { return board; }
    
    /**
     * getPieceAt
     * returns the piece at board[x][y], duh
     * Ax + By + C = i, where A = -.5, B = -4.5, C = 35.5
     */
    public byte getPieceAt(int x, int y) { return board[(byte)(x * -.5 + y * -4.5 + 35.5)]; }
    
	/**
	 * getKingAt
	 * returns the king at board[x][y]
	 * legacy function; totally useless
	 */
	public byte getKingAt(Coord c) {
		byte piece = getPieceAt(c.x, c.y);
		return piece < 4 ? 0 : piece;
	}
     
    
    /**
     * makeMove
     * performs necessarily valid set of moves on board
     */
    public byte makeMove(Move m) {
        Coord move = m.start(), nextMove, jumpedPiece;
        byte numJumped = 0;
        int moveIndex, nextMoveIndex;
        do {
            nextMove = m.next();
            moveIndex = (byte)(move.x * -.5 + move.y * -4.5 + 35.5);
            nextMoveIndex = (byte)(nextMove.x * -.5 + nextMove.y * -4.5 + 35.5);
            // generally speaking, this should be valid
            if (board[moveIndex] != 0 && board[nextMoveIndex] == 0) {
            	if (moveIndex > nextMoveIndex)
            		if (nextMoveIndex - moveIndex == 10) {				// forward left jump
            			board[moveIndex+5] = 0;
            			numJumped++;
            		} else if (nextMoveIndex - moveIndex == 8) {		// forward right jump
            			board[moveIndex+4] = 0;
            			numJumped++;
            		}
            	else if (moveIndex < nextMoveIndex)
            		if (moveIndex - nextMoveIndex == 10) {				// backward right jump
            			board[moveIndex-5] = 0;
            			numJumped++;
            		} else if (moveIndex - nextMoveIndex == 8) {		// backward left jump
            			board[moveIndex-4] = 0;
            			numJumped++;
            		}
                if (nextMoveIndex > 31 || nextMoveIndex < 5)
                	board[nextMoveIndex] = (byte)(player + 3);
                else
                	board[nextMoveIndex] = player;
                	
                board[moveIndex] = 0;
            } 
            // wtf, get out of here
            else	return -1;
            
            move = nextMove;
            
        } while (!m.isEmpty());
        
        nextPlayer();
        return numJumped;
    }
    
    /**
     * getAdjacentTo
     * returns coordinates of squares directly adjacent to given coordinate
     */
    public Coord[] getAdjacentTo(Coord c) {
    	int index = (byte)(c.x * -.5 + c.y * -4.5 + 35.5);
    	Coord[] neighbors = new Coord[4];
    	int num = 0;
    	if (index > 4) {
    		if (board[index-5] != -1)	{ neighbors[num] = new Coord(c.x+1, c.y-1); num++; }
    		if (board[index-4] != -1)	{ neighbors[num] = new Coord(c.x-1, c.y-1); num++; }
    	}    	
    	if (index < 32) {
    		if (board[index+5] != -1)	{ neighbors[num] = new Coord(c.x-1, c.y+1); num++; }
    		if (board[index+4] != -1)	{ neighbors[num] = new Coord(c.x+1, c.y+1); num++; }
    	}
    	
        if (num == 4)
            return neighbors;
        if (num == 0)
            return null;
        
        Coord adjStates[] = Arrays.copyOf(neighbors, num); // truncate the array
        return adjStates;
    }
    
    /**
     * printBoard
     */
    public void printBoard() {
    	for (int i=1; i<36; i++) {
    		if (i==9||i==18||i==27) { i++; continue; }
    		System.out.println(board[i]);
    	}    	
    }
    
    /**
     * evaluate
     * returns a polynomial score of various terms
     */
    public long evaluate(byte player) {
    	//byte[] board = new byte[36]; // [1, 35], excluding 0, 9, 18, 27
    	int y = 0, j = 1;
    	
    	// generate the fucking genius array
    	/*
    	for (int x = 0; x < 8; x+=2) {
    		if (x%2 == 0)	y = 0;
    		else			y = 1;
    		for ( ; y < 8; y+=2)
    			board[j] = this.board[x][y];
    		j++;
    		if (j == 9 || j == 18 || j == 27) {
    			board[j] = -1;
    			j++;
    		}
    	}*/
    	
    	byte adv=0, apex=0, back=0, cent=0, cntr=0, corn=0, cramp=0;
    	byte deny=0, dia=0, diav=0, dyke=0;
    	byte exch=0, expos=0, fork=0, gap=0, guard=0, hole=0, kcent=0;
    	byte mob=0, mobil=0, move=0, node=0;
    	byte oreo=0, pole=0, threat=0;
    	
    	byte passive;
    	if (this.player != player)	// we are passive
    		passive = this.player;
    	else						// else, player is passive
    		passive = player;
    	
    	// ADV
    	// +1 for passive in rows 5, 6 (red); -1 for passive in rows 3, 4 (red)
		for (int i = 26; i>18; i--)
			if (board[i] == passive)
				if (passive == 1)		// red, at the top
					adv--;
				else						// black, at the top
					adv++;
		for (int i = 17; i>9; i--)
			if (board[i] == passive)
				if (passive == 1)		// red, at the bottom
					adv++;
				else						// black, at the bottom
					adv--;
    	
    	// APEX
    	// no kings && active in 29 OR 7 && passive in neither
    	if ((board[29] != passive && board[7] != passive) && (board[29] == player || board[7] == player))
    		apex = -1;
    	if (apex == -1) {
    		for (int i =1; i<36; i++) {
    			if (i==9||i==18|i==27) {i++; continue; }
    			if (board[i] != 4 && board[i] != 5)
    				apex++;
    			
    			if (board[i] == 4 && player == 1)	{	// an active red king
    				back++;
    				guard++;
    			} else if (board[i] == 5 && player == 2)	{	// an active black king
    				back++;
    				guard++;
    			}
    		}
    		if (apex == 31)	// means no kings were found
    			apex = -1;
    		else
    			apex = 0;
    	}
    	
    	// BACK
    	// no active kings && passive pieces in 1 && 3 OR 33 && 35
    	if (back == 0 && (
    		(board[35] == passive || board[35] == passive+3 && board[33] == passive || board[33] == passive+3) || 
    		(board[1] == passive || board[1] == passive+3 && board[3] == passive || board[1] == passive+3)))
    		back = 1;
    	
    	// CENT
    	// +1 for passive in 11, 12, 15, 16, 20, 21, 24, 25
    	for (int i = 11; i<24; i+=4) {
    		if (board[i] == passive)		// passive cnt
    			cent++;
    		if (board[i+1] == passive)
    			cent++;
    		if (board[i] == player)		// active cnt
    			cntr++;
    		if (board[i+1] == player)
    			cntr++;
    		if (i == 15)
    			i++;
    	}
    	
    	// CNTR
    	// +1 for active or active can move into 11, 12, 15, 16, 20, 21, 24, 25 (include jumps later?)
    	// red + 30, 29, 28, 26, 19, 17; black + 6, 7, 8, 10, 17, 19
    	if (player == 1) {	// active player is red
    		if (board[30] == 1 || board[30]==4) cntr++;
    		if (board[29] == 1 || board[29]==4) cntr++;
    		if (board[28] == 1 || board[28]==4) cntr++;
    		if (board[26] == 1 || board[26]==4) cntr++;
    		if (board[19] == 1 || board[19]==4) cntr++;
    		if (board[17] == 1 || board[17]==4) cntr++;
    		
    		// CRAMP for black, passive
    		if ((board[14] == 2 || board[14]==5) && 
    			(board[15] == 2 || board[15]==5 || board[10] == 2 || board[10]==5) && 
    			((board[19] == 1 || board[19]==4) && (board[23] == 1 || board[23]==4) && (board[24] == 1 || board[24]==4) && (board[28] == 1 || board[28]==4)))
    			cramp = 2;
    		
    	} else {
    		if (board[17] == 2 || board[17]==5) cntr++;
    		if (board[19] == 2 || board[19]==5) cntr++;
    		if (board[6] == 2 || board[6]==5) cntr++;
    		if (board[7] == 2 || board[7]==5) cntr++;
    		if (board[8] == 2 || board[8]==5) cntr++;
    		if (board[10] == 2 || board[10]==5) cntr++;
    		
    		// CRAMP for red, passive
    		if ((board[22] == 1 || board[22]==4) && 
    			(board[21] == 1 || board[21]==4 || board[26] == 1 || board[26]==4) && 
    			((board[8] == 2 || board[8] == 5) && (board[12] == 2 || board[12] ==5) && (board[13] == 2 ||board[13]==5) && (board[17] == 2 || board[17]==5)))
    			cramp = 2;
    	}
    	
    	// CORN (TODO)
    	// wtf is material credit?
    	
    	// CRAMP (see CNTR)
    	// +2 for (red) passive in 22 && 21 OR 26 && (black) active in 8, 12, 13, 17
    	// (black) passive in 14 && 15 OR 10 && (red) active in 19, 23, 24, 28
    	
    	// DENY (TODO) eval in ValidMoves
    	// +1 per squre in MOB if on next move, a piece occupying square can be captured without exchange
    	
    	// DIA (TODO)
    	// +1 per passive piece located in diagonal files terminating in double-corner squares
    	
    	// DIAV (TODO)
    	// +1/2 per passive 2 squares away from double corner diagonal files
    	// +1 per passive 1 square away
    	// +3/2 per passive in double corner file
    	
    	// DYKE  (see GIGANTIC ITERATION)
    	// +1 per passive string of 3 pieces in adjacent diagonal squares
    	
    	// EXCH (TODO) eval in ValidMoves
    	// +1 per square to which active side may advance a piece and force an exchange
    	
    	// EXPOS  (see GIGANTIC ITERATION)
    	// +1 per passive piece flanked along a diagonal by two empty squares
    	
    	// FORK (TODO) eval in ValidMoves
    	// +1 per situation in which 2 adjacent passive pieces in row and 3 empty squares such that active player
    	// in occupying one of them, threaten sure capture of one or the other passive pieces
    	
    	// GAP  (see GIGANTIC ITERATION)
    	// +1 per single, empty square that separates two passive pieces along a diagonal,
    	// or separates a passive piece from the edge of the board
    	
    	// GUARD (see OREO)
    	// +1 if no active kings && if either the Bridge (BACK) or Triangle of Oreo (OREO) is occupied by passive
    		
    	// HOLE  (see GIGANTIC ITERATION)
    	// +1 per empty square surrounded by 3 or more passive
    	
    	// KCENT
    	// +1 for passive king in 11, 12, 15, 16, 20, 21, 24, 25
    	for (int i = 11; i<24; i+=4) {
    		if (board[i] == passive + 3)	// passive king
    			kcent++;
    		if (board[i+1] == passive + 3)
    			kcent++;
    		if (i == 15)
    			i++;
    	}
    	
    	// MOB (TODO) eval in ValidMoves
    	// +1 per square to which active side could move 1 or more pieces normally (disregard jump possibilities)
    	
    	// MOBIL (TODO) eval in ValidMoves
    	// diff between MOB and DENY
    	
    	// MOVE (TODO)
    	// +1 if total piece count is even (<24) (2, 3 for king) and if an odd number of pieces are in move system
    	// defined by vertical files in 28, 29, 30, 31
    	
    	// NODE  (see GIGANTIC ITERATION)
    	// +1 per passive piece surrounded by atleast 3 empty squares
    	
    	// OREO
    	// +1 if no passive kings and passive in 29, 33, 34 (red) or 2, 3, 7 (black)
    	if (passive == 1)	// passive red
    		if (board[29] == 1 && board[33] == 1 && board[34] == 1) {
    			oreo = 1;
    			for (int i = 1; i<36; i++)
    				if (board[i] == 4) {
    					oreo = 0;
    					break;
    				}		
    		}
    	else
    		if (board[2] == 2 && board[3] == 2 && board[7] == 2) {
    			oreo = 1;
    			for (int i = 1; i<36; i++)
    				if (board[i] == 5) {
    					oreo = 0;
    					break;
    				}
    		}
    		
    	// GUARD
    	if (back == 1 || (guard == 0 && oreo == 1))
    		guard = 1;
    	
    	// POLE (see GIGANTIC ITERATION)
    	// +1 per passive piece completely surrounded by empty squares
    	
    	// GIGANTIC ITERATION block for various parameters
    	for (int i = 1; i < 36; i++) {
    		byte empty = 0, friendly = 0, leftdiag = 0, rightdiag = 0;
    		if (i==9||i==18||i==27) {i++; continue; }
    		
    		// a passive piece
    		if (board[i] == passive || board[i] == passive+3) {
	    		if (i > 4) {	// exclude bottom row
	    			if (board[i-5] == 0) {					// back right
	    				empty++; leftdiag++;
	    			}					
	    			else if (board[i-5] == passive || board[i+5] == passive+3) 
	    				friendly++;
	    			
	    			if (board[i-4] == 0) {					// back left
	    				empty++; rightdiag++;
	    			}					
	    			else if (board[i-4] == passive || board[i+5] == passive+3) 
	    				friendly++;
	    		}
	    		if (i < 32) {	// exclude top row
		    		if (board[i+4] == 0) {					// forward right
		    			empty++; rightdiag++;
		    		}
		    		else if (board[i+4] == passive || board[i+5] == passive+3) 
		    			friendly++;
		    		
		    		if (board[i+5] == 0) {					// forward left
		    			empty++; leftdiag++;
		    		}
		    		else if (board[i+5] == passive || board[i+5] == passive+3) 
		    			friendly++;
	    		}
	    		// NODE
	    		if (empty > 3) {
	    			node++;
	    			// POLE
	    			if (empty == 4)
	    				pole++;
	    		}
	    		// EXPOS
	    		if (leftdiag == 2 || rightdiag == 2)
	    			expos++;
	    		// DYKE
	    		if (friendly >= 2)
	    			dyke++;
	    	}
	    	
	    	// an empty space
	    	else if (board[i] == 0) {						
	    		if (i > 4) {
	    			if (board[i-5] == passive || board[i-5]==passive+3) {					// back right
	    				friendly++; leftdiag++;
	    			}
	    			
	    			if (board[i-4] == passive || board[i-4]==passive+3) {					// back left
	    				friendly++; rightdiag++;
	    			}					
	    		}
	    		if (i < 32) {
	    			if (board[i+5] == passive || board[i+5]==passive+3) {
	    				friendly++; leftdiag++;
	    			}
	    			
	    			if (board[i+4] == passive || board[i+4]==passive+3) {
	    				friendly++; rightdiag++;
	    			}
	    		}
	    		// HOLE
	    		if (friendly >= 3)
	    			hole++;
	    		// GAP
	    		if (rightdiag == 2 || leftdiag == 2 || 
	    			(rightdiag == 1 && board[i-4] == -1) || (leftdiag == 1 && board[i-5] == -1))
	    			gap++;
	    	}
    		
    	}
    	
    	// THRET (TODO) eval in ValidMoves
    	// +1 per square to which an active piece may be moved and then threaten capture of passive piece in subsequent move
    	
    	return 0;
    }
    
}